
using System.Drawing;

using SharpWind.Input;

namespace SharpWind.Gui.Controls
{
	public class TextBox : TextBoxBase
	{
		private bool readOnly = false;

		private bool cursor = false;

		private float cursorTime = 0f;

		private int currentLine = 0;

		public TextBox() : base( "textbox" )
		{
			Size = new SizeF( 100, 20 );
			this.lines.Add( string.Empty );
		}

		internal override void KeyDown( KeyboardEventArgs e )
		{
			if( Enabled && !ReadOnly && Visible )
			{
				RemoveCursor();

				if( e.KeyValue != char.MaxValue && e.KeyValue != char.MinValue )
				{
					this.label.Text += e.KeyValue;
					AddCharToCurrentLine( e.KeyValue );
				}
				else if( e.KeyCode == Key.Space )
				{
					this.label.Text += ' ';
					AddCharToCurrentLine( ' ' );
				}
				else if( e.KeyCode == Key.BackSpace )
				{
					this.label.Text = this.label.Text.Substring( 0, this.label.Text.Length - 1 );
					RemoveCharFromCurrentLine();
				}
				else if( e.KeyCode == Key.Return )
				{
					this.label.Text += '\n';
					AddCharToCurrentLine( '\n' );
					AddNewLine();

					int amount = this.lines.Count - this.maxLines - this.startLine;
					if( amount > 0 )
					{
						MoveTextLinesUp( amount );
						this.vScrollBar.Maximum = this.startLine;
						this.vScrollBar.Value   = this.startLine;
						this.vScrollBar.Enabled = this.startLine == 0 ? false : true;
					}
				}
			}
		}

		internal override void Render()
		{
			if( Visible )
			{
				base.Render();
				RenderCursor();
			}
		}

		private void RenderCursor()
		{
			if( Enabled && !ReadOnly )
			{
				this.cursorTime += Engine.Instance.Timer.ElapsedTime;
				if( this.cursorTime > 0.5f )
				{
					this.cursorTime = 0f;
					this.cursor = !this.cursor;
				}

				if( this.cursor )
				{
					if( this.label.Text.Length == 0 )
					{
						this.label.Text += '|';
					}
					else if( this.label.Text[this.label.Text.Length - 1] != '|' )
					{
						this.label.Text += '|';
					}
				}
				else
				{
					RemoveCursor();
				}
			}
		}

		private void RemoveCursor()
		{
			if( this.label.Text.Length > 0 && this.label.Text[this.label.Text.Length - 1] == '|' )
			{
				this.label.Text = this.label.Text.Substring( 0, this.label.Text.Length - 1 );
			}
		}

		private void AddCharToCurrentLine( char c )
		{
			this.lines[this.currentLine] += c;
		}

		private void RemoveCharFromCurrentLine()
		{
			if( this.lines[this.currentLine].Length == 0 && this.lines.Count > 1 )
			{
				RemoveLine();
				this.lines[this.currentLine] = this.lines[this.currentLine].Substring( 0, this.lines[this.currentLine].Length - 1 );	
				MoveTextLinesDown( 1 );
				this.vScrollBar.Maximum = this.startLine;
				this.vScrollBar.Value	= this.startLine;
				this.vScrollBar.Enabled = this.startLine == 0 ? false : true;
			}
			else
			{
				this.lines[this.currentLine] = this.lines[this.currentLine].Substring( 0, this.lines[this.currentLine].Length - 1 );
			}
		}

		private void AddNewLine()
		{
			this.currentLine++;
			this.lines.Add( string.Empty );
		}

		private void RemoveLine()
		{
			this.lines.RemoveAt( this.currentLine );
			this.currentLine--;
		}

		private void PreprocessText()
		{
			foreach( char character in this.label.Text )
			{
				AddCharToCurrentLine( character );

				if( character == '\n' )
				{
					AddNewLine();
				}
			}

			int amount = this.lines.Count - this.maxLines - this.startLine;
			if( amount > 0 )
			{
				MoveTextLinesUp( amount );
			}

			this.vScrollBar.Maximum = this.startLine;
			this.vScrollBar.Value   = this.startLine;
			this.vScrollBar.Enabled = this.startLine == 0 ? false : true;
		}

		public bool ReadOnly
		{
			get
			{
				return this.readOnly;
			}
			set
			{
				this.readOnly = value;
			}
		}

		public string Text
		{
			get
			{
				return this.label.Text;
			}
			set
			{
				if( this.label.Text != value )
				{
					this.label.Text = value;
					PreprocessText();
				}
			}
		}

		public bool WordBreak
		{
			get
			{
				return this.label.WordBreak;
			}
			set
			{
				this.label.WordBreak = value;
			}
		}

		public string[] Lines
		{
			get
			{
				return this.lines.ToArray();
			}
		}
	}
}
